package ygo

import "fmt"

func cop0(
		cop0Decode         chan uint32,
		aluCop0_exception  chan int32,
		decodeCop0         chan DECO,
		pcCop0             chan uint32,
		cop0Pc             chan uint32) {

	var (
		epc uint32
		v_exception int32
		//error_pc uint32
	)

	// R/W bit 2 (Error Level)
	status_ERL :=  01
	// R/W bit 1 (Exception Level)
	status_EXL := 00
	// R/W bit 0 (Interruption Enable)
	status_IE := 00
	// R bit 15..8 (Pending Hardware Interruptions)
	cause_IP := 00000000
	/*
	// R bit 6..2 (Exception Code)
	cause_ExCode := 00000
	// R   bit 31 (Branch Delay Slot)
	cause_BD := uint32(00)
	// R/W bit 22 
	status_BEV := 01 
	// R/W bit 23 (Interruption vector)
	cause_IV := 00 
	*/

	cop0Decode <- CONTINUE
	for{
		interruptions_are_enable := -(status_ERL) & -(status_EXL) & status_IE;
		has_pending_interruption := interruptions_are_enable & -cause_IP //= 00000000)

		/*
		v_bds := deco.CP0_BDS
		*/
fmt.Println("[COP0] ESPERANDO DECODE")
		deco :=<- decodeCop0

		switch(deco.CP0_COMMAND){
			case NOTHING:
				fmt.Printf("[COP0] DECO <-- DECODE (cmd: NOTHING, cp0bds: %d)\n",deco.CP0_BDS)

				if has_pending_interruption == 1 {
					fmt.Println("[COP0] CMD --> DECODE (INTERRUPTION)")
					cop0Decode <- INTERRUPTION

					current_pc :=<- pcCop0
					fmt.Printf("[COP0] current_pc <-- COP0 (%d)\n",current_pc)

					if status_EXL == 0 {
						if deco.CP0_BDS == 1 {
							epc = current_pc - INSTRUCTION_SIZE
							fmt.Println("[COP0] EPC =",epc)
						} else {
							epc = current_pc
							fmt.Println("[COP0] EPC =",epc)
						}
					} else {
						status_EXL = 1
					}
				} else {
					fmt.Println("[COP0] CMD --> DECODE (CONTINUE)")
					cop0Decode <- CONTINUE
				}

			case EXCEPTION_RETURN:
				fmt.Printf("[COP0] DECO <-- DECODE (cmd: EXCEPTION_RETURN, cp0bds: %d)\n",deco.CP0_BDS)

			case WAIT_EXCEPTION:
				fmt.Printf("[COP0] DECO <-- DECODE (cmd: WAIT_EXCEPTION, cp0bds: %d)\n",deco.CP0_BDS)

				v_exception =<- aluCop0_exception
				fmt.Println("[COP0] EXCEPTION <-- ALU")

				switch {
					case has_pending_interruption == 1:
						/*
						if v_exception == EX_INTERRUPTION {
							//-- no exception from alu, 				//?????????
							//--so current instruction is not cancelled		//?????????
							cop0Decode <- INTERRUPTION
							v_bds := "0";
						}else{
							//-- exception sent by ALU
							//-- current instruction is cancelled,
							//-- and must be rexecuted
							cop0Decode <- CORE_INTERRUPTION
						}
						cause_ExCode = EX_INTERRUPTION
						cause_BD = v_bds
						current_pc :=<- pcCop0
						fmt.Printf("[COP0] current_pc <-- COP0 (%d)\n",current_pc)

						if status_EXL == 00 {
							if v_bds == 01 {
								EPC := current_pc - INSTRUCTION_SIZE;
							}else{
								EPC := current_pc;
							}
							status_EXL := "1";
						}else{
							status_EXL := "1";
						}

						if status_BEV == 01 && cause_IV == 01{ //-- bootstrap and int vector
							cop0Pc <- IV_BS_ADDRESS
						}else if status_BEV == 01 && cause_IV == 00{ // -- bootstrap
							cop0Pc <- BS_EXCEPTION_ADDRESS
						}else if status_BEV == 00 && cause_IV == 01{ // -- int vector
							cop0Pc <- IV_NORMAL_ADDRESS
						}else{//-- normal
							cop0Pc <- NORMAL_EXCEPTION_ADDRESS
						}
						*/
					case (v_exception != EX_INTERRUPTION):
						
					default:
						fmt.Println("[COP0] CMD --> DECODE (CONTINUE)")
						cop0Decode <- CONTINUE
				 }

			case WAIT_INTERRUPTION:
				fmt.Printf("[COP0] DECO <-- DECODE (cmd: WAIT_INTERRUPTION, cp0bds: %d)\n",deco.CP0_BDS)

			case MOVE_TO_CP0:
				fmt.Printf("[COP0] DECO <-- DECODE (cmd: MOVE_TO_CP0, cp0bds: %d)\n",deco.CP0_BDS)

			case MOVE_FROM:
				fmt.Printf("[COP0] DECO <-- DECODE (cmd: MOVE_FROM, cp0bds: %d)\n",deco.CP0_BDS)

			case SYSCALL:
				fmt.Printf("[COP0] DECO <-- DECODE (cmd: SYSCALL, cp0bds: %d)\n",deco.CP0_BDS)
		}
	}
}
